package com.itlong.cloud.property.service.impl;

import com.itlong.cloud.POJO.DTO.property.*;
import com.itlong.cloud.POJO.PO.BuildInfoPO;
import com.itlong.cloud.POJO.PO.UnitInfoPO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectBuildInfoVO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectBuildSimpleInfoExVO;
import com.itlong.cloud.POJO.VO.property.PropertyProjectBuildSimpleInfoVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.property.dao.IPropertyBuildInfoDao;
import com.itlong.cloud.property.dao.IPropertyUnitInfoDao;
import com.itlong.cloud.property.service.IPropertyBuildInfoService;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.words.NumberHandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
* <desc>
*       楼栋信息处理接口实现.
* </desc>
*
* @createDate 2017-09-22
*/
@Service
public class PropertyBuildInfoServiceImpl implements IPropertyBuildInfoService {

    private final IPropertyBuildInfoDao iPropertyBuildInfoDao; //楼栋信息数据库访问对象

    private final IPropertyUnitInfoDao iPropertyUnitInfoDao; //单元信息数据库访问对象

    @Autowired
    public PropertyBuildInfoServiceImpl(IPropertyBuildInfoDao iPropertyBuildInfoDao, IPropertyUnitInfoDao iPropertyUnitInfoDao) {
        this.iPropertyBuildInfoDao = iPropertyBuildInfoDao;
        this.iPropertyUnitInfoDao = iPropertyUnitInfoDao;
    }

    /**
    * <desc>
    *       保存楼栋信息（含批量添加单元信息）
    * </desc>
    *
    * @param propertyProjectSaveBuildInfoDTO 添加楼栋信息数据传输对象
    * @return 受影响的行数
    * @author LewisLouis
    * @createDate 2017-09-21
    */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer saveBuildInfo(PropertyProjectSaveBuildInfoDTO propertyProjectSaveBuildInfoDTO) throws Exception {

        //组装楼栋信息数据库实体对象
        BuildInfoPO buildInfoPO = getBuildPOBySaveDTO(propertyProjectSaveBuildInfoDTO);

        //将楼栋信息实体对象保存到数据库
       int intRes = iPropertyBuildInfoDao.save( SqlUtil.durableData(buildInfoPO, PlatformConstants.TABLE_SAVE));


       //批量保存单元实体对象到数据库（若无需保存）
        int unitCount = propertyProjectSaveBuildInfoDTO.getUnitCount();
        if (unitCount <= 0){
           return  intRes;
        }

        List<String> unitAliasHasUsed = iPropertyUnitInfoDao.getUnitAliasByProjectId(propertyProjectSaveBuildInfoDTO.getProjectId());
       UnitInfoPO  oneUnitInfoPO;
       Map oneRowMap;
       ArrayList<Map<String,Object>> rowsList = new ArrayList<>() ;
       for (int unitIndex = 1; unitIndex <= propertyProjectSaveBuildInfoDTO.getUnitCount(); unitIndex++){

           oneUnitInfoPO = this.getUnitPOByBuildPO(unitAliasHasUsed,buildInfoPO,unitIndex,propertyProjectSaveBuildInfoDTO.getProjectId());
           oneRowMap = SqlUtil.durableData(oneUnitInfoPO, PlatformConstants.TABLE_SAVE);
           rowsList.add(oneRowMap);
       }
       intRes = iPropertyUnitInfoDao.batchSave(rowsList);
       return intRes;

    }


    /**
    * <desc>
    *       分页查询楼栋信息.
    * </desc>
    *
    * @param propertyProjectGetBuildInfoDTO 分页查询楼栋信息数据传输对象
    * @return 分页查询结果对象
    * @author LewisLouis
    * @createDate 2017-09-25
    */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<PropertyProjectBuildInfoVO> getPage(PropertyProjectGetBuildInfoDTO propertyProjectGetBuildInfoDTO) throws Exception {
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(propertyProjectGetBuildInfoDTO);
        params.put("projectId",propertyProjectGetBuildInfoDTO.getProjectId());

        Page<PropertyProjectBuildInfoVO> page = new Page<>();
        page.getPage().setPageSize(propertyProjectGetBuildInfoDTO.getPageSize());
        page.getPage().setCurrentPage(propertyProjectGetBuildInfoDTO.getCurrentPage());
        params.put("startSlip",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        //填充返回数据集
        List<PropertyProjectBuildInfoVO> propertyProjectBuildInfoVOS = iPropertyBuildInfoDao.getPageList(params);
        page.setRows(propertyProjectBuildInfoVOS, iPropertyBuildInfoDao.getRecordCount(params));
        return page;
    }

    /**
     * <desc>
     *      修改楼栋信息【根据楼栋Id（BuildId）】
     * </desc>
     *
     * @param propertyProjectUpdateBuildInfoDTO 修改楼栋信息数据传输对象
     * @return 受影响的行数
     * @author LouisLewis
     * @createDate 2017-09-26
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer updateBuildInfo(PropertyProjectUpdateBuildInfoDTO propertyProjectUpdateBuildInfoDTO)throws Exception
    {
        BuildInfoPO buildInfoPO = new BuildInfoPO();
        BeanUtils.copyProperties(propertyProjectUpdateBuildInfoDTO,buildInfoPO);
        if ((propertyProjectUpdateBuildInfoDTO.getGroundFloorNum() != null)
                && (propertyProjectUpdateBuildInfoDTO.getUndergroundFloorNum() != null)){
                    int floorNum = propertyProjectUpdateBuildInfoDTO.getGroundFloorNum()
                + propertyProjectUpdateBuildInfoDTO.getUndergroundFloorNum();
            buildInfoPO.setFloorNum(floorNum);
        }
        buildInfoPO.setProjectId(null); //不允许更新项目编号
        buildInfoPO.setBuildNum(null); //不允许更新楼栋编号
        buildInfoPO.setCreateTime(null); //不允许更新创建时间
        buildInfoPO.setUpdateTime(new Date());

        //解决楼栋类型无法修改为无的问题
        Map<String, Object> map = SqlUtil.durableData(buildInfoPO, PlatformConstants.TABLE_UPDATE);
        if (null == propertyProjectUpdateBuildInfoDTO.getBuildType()){
            List<Map<String, Object>> updates = (List<Map<String, Object>>)map.get("list");
            Map<String,Object> newFileds = new HashMap<>();
            newFileds.put("columnName","build_type");
            newFileds.put("columnValue",null);
            updates.add(newFileds);
        }
        return iPropertyBuildInfoDao.update(map);
    }

    /**
     * <desc>
     *      逻辑删除楼栋信息【根据楼栋Id（BuildId）】
     * </desc>
     *
     * @param buildId 待删除的楼栋Id
     * @return 受影响的行数
     * @author LouisLewis
     * @createDate 2017-09-26
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer removeBuildInfo(String buildId) {

        //逻辑删除楼栋下的单元
        PropertyProjectRemoveUnitInfoDTO propertyProjectRemoveUnitInfoDTO = new PropertyProjectRemoveUnitInfoDTO();
        propertyProjectRemoveUnitInfoDTO.setBuildId(buildId);
        Integer intUnitRes = iPropertyUnitInfoDao.remove(propertyProjectRemoveUnitInfoDTO);

        //逻辑删除楼栋信息
        Integer intBuildRes = iPropertyBuildInfoDao.remove(buildId);

        return  intBuildRes + intUnitRes;
    }


    /**
     * <desc>
     *      精确查询，获取单个楼栋信息
     * </desc>
     *
     * @param propertyProjectGetBuildInfoDTO 查询楼栋信息数据传输对象
     * @return 按创建时间降序排列，首个符合查询条件的楼栋信息
     * @author LouisLewis
     * @createDate 2017-09-25
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public PropertyProjectBuildInfoVO getOneBuildInfo(PropertyProjectGetBuildInfoDTO propertyProjectGetBuildInfoDTO)
    {
        BuildInfoPO inBuildInfoPO = new BuildInfoPO();
        BeanUtils.copyProperties(propertyProjectGetBuildInfoDTO,inBuildInfoPO);
        PropertyProjectBuildInfoVO oneBuildInfo = iPropertyBuildInfoDao.getOneBuildInfo(inBuildInfoPO);
        if (oneBuildInfo != null) {
            Integer elevatorCount = iPropertyBuildInfoDao.getBuildElevatorCount(oneBuildInfo.getBuildId());
            oneBuildInfo.setHasElevator(elevatorCount > 0 ? 1 : 0);
        }
        return oneBuildInfo;
    }

    /**
     * <desc>
     *      获取指定项目下的楼栋简单信息（楼栋id ,楼栋名称）列表
     * </desc>
     *
     * @param propertyProjectGetBuildSimpleInfoDTO 查询楼栋简单信息数据传输对象
     * @return 楼栋简单信息（楼栋id ,楼栋名称）列表
     * @author LewisLouis
     * @createDate 2017-09-28
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<PropertyProjectBuildSimpleInfoVO> getPageBuildSimpleInfoList(
            PropertyProjectGetBuildSimpleInfoDTO propertyProjectGetBuildSimpleInfoDTO) throws  Exception{
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(propertyProjectGetBuildSimpleInfoDTO);
        params.put("projectId",propertyProjectGetBuildSimpleInfoDTO.getProjectId());
        Page<PropertyProjectBuildSimpleInfoVO> page = new Page<>();
        page.getPage().setPageSize(propertyProjectGetBuildSimpleInfoDTO.getPageSize());
        page.getPage().setCurrentPage(propertyProjectGetBuildSimpleInfoDTO.getCurrentPage());
        params.put("startSlip",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        //填充返回数据集
        List<PropertyProjectBuildSimpleInfoVO> propertyProjectBuildSimpleInfoVOS = iPropertyBuildInfoDao.getPageBuildSimpleInfoList(params);
        page.setRows(propertyProjectBuildSimpleInfoVOS, iPropertyBuildInfoDao.getRecordCount(params));

        return page;
    }

    /**
     * <desc>
     *      分页查询指定项目下的楼栋简单扩展信息（楼栋id ,楼栋名称、楼栋下的房间数量）列表
     * </desc>
     *
     * @param propertyProjectGetBuildSimpleInfoDTO 查询楼栋简单扩展信息数据传输对象
     * @return 楼栋简单扩展信息（楼栋id ,楼栋名称、楼栋下的房间数量）列表
     * @author LewisLouis
     * @createDate 2017-11-13
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<PropertyProjectBuildSimpleInfoExVO> getPageBuildSimpleInfoExList(PropertyProjectGetBuildSimpleInfoDTO propertyProjectGetBuildSimpleInfoDTO) throws Exception {
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(propertyProjectGetBuildSimpleInfoDTO);
        params.put("projectId",propertyProjectGetBuildSimpleInfoDTO.getProjectId());
        Page<PropertyProjectBuildSimpleInfoExVO> page = new Page<>();
        page.getPage().setPageSize(propertyProjectGetBuildSimpleInfoDTO.getPageSize());
        page.getPage().setCurrentPage(propertyProjectGetBuildSimpleInfoDTO.getCurrentPage());
        params.put("startSlip",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        //填充返回数据集
        List<PropertyProjectBuildSimpleInfoExVO> pageBuildSimpleInfoxExList  = iPropertyBuildInfoDao.getPageBuildSimpleInfoExList(params);
        page.setRows(pageBuildSimpleInfoxExList, iPropertyBuildInfoDao.getRecordCount(params));

        return page;
    }

    /**
     * <desc>
     *      获取指定项目的最小可用楼栋编号buildNum
     * </desc>
     *
     * @param projectId 项目id
     * @return 最小可用的楼栋编号
     * @author wangzhi
     * @createDate 2018/05/29
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public String getMinAvaliableBuildNumByProjectId(String projectId) {
        return getMinAvailableBuildNum(projectId);
    }

    /**
    * <desc>
    *       获取指定项目的最小可用楼栋编号（BuildNum）.
    * </desc>
    *
    * @param projectId 指定项目编号
    * @return 最小可用楼栋编号（BuildNum）.
    * @author LewisLouis
    * @createDate 2017-09-21
    */

    private String getMinAvailableBuildNum(String projectId)
    {
        //从数据库中查询出所有已使用的楼栋编号
        List<String> buildNumList = iPropertyBuildInfoDao.getBuildNumList(projectId);
        //初始化为最小楼栋编号
        String oneBuildNum = NumberHandlerUtil.numFormatToString(PlatformConstants.MIN_BUILD_NUM,3);

        //该项目下还未设置楼栋信息时，直接返回最小楼栋编号
        if (buildNumList.isEmpty())
        {
            return oneBuildNum;
        }
        //从最小楼栋编号到最大楼栋编号,依次遍历,检查楼栋编号是否已使用，若未使用，则直接返回
        for (int buildIndex = PlatformConstants.MIN_BUILD_NUM;
             buildIndex <= PlatformConstants.MAX_BUILD_NUM; buildIndex++ )
        {
            oneBuildNum = NumberHandlerUtil.numFormatToString(buildIndex,3);
            if (!buildNumList.contains(oneBuildNum))
            {
                return oneBuildNum;
            }
        }
        return oneBuildNum;

    }


    /**
    * <desc>
    *       根据数据传输对象返回楼栋信息数据库实体对象，用于保存到数据库
    * </desc>
    *
    * @param propertyProjectSaveBuildInfoDTO 添加楼栋信息数据传输对象
    * @return 楼栋信息数据库实体对象
    * @author LewisLouis
    * @createDate 2017-09-21
    */
    private BuildInfoPO getBuildPOBySaveDTO(PropertyProjectSaveBuildInfoDTO propertyProjectSaveBuildInfoDTO)
    {
        String projectId = propertyProjectSaveBuildInfoDTO.getProjectId();
//        String newAvailableBuildNum = getMinAvailableBuildNum(projectId);
        BuildInfoPO buildInfoPO = new BuildInfoPO();
        BeanUtils.copyProperties(propertyProjectSaveBuildInfoDTO,buildInfoPO);
//        buildInfoPO.setBuildNum(newAvailableBuildNum);
        int floorNum = propertyProjectSaveBuildInfoDTO.getGroundFloorNum()
                + propertyProjectSaveBuildInfoDTO.getUndergroundFloorNum();
        buildInfoPO.setFloorNum(floorNum);
        buildInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
        Date createTime = new Date();
        buildInfoPO.setCreateTime(createTime);
        buildInfoPO.setUpdateTime(createTime);
        String buildId = LogicIdUtil.bussinessId();
        buildInfoPO.setBuildId(buildId);
        buildInfoPO.setProjectId(projectId);
        return buildInfoPO;
    }



    /**
     * <desc>
     *      根据楼栋数据库实体对象和单元序号返回默认单元信息数据库实体对象，用于保存到数据库
     * </desc>
     *
     * @param unitAliassHasUsed  已使用的单元代号列表
     * @param buildInfoPO  楼栋信息实体类
     * @param unitIndex 单元序号
     * @return 单元信息数据库实体对象
     * @author LewisLouis
     * @createDate 2017-09-22
     */
    private UnitInfoPO getUnitPOByBuildPO(List<String> unitAliassHasUsed, BuildInfoPO buildInfoPO, int unitIndex,String projectId){
        UnitInfoPO unitInfoPO = new UnitInfoPO();
        unitInfoPO.setBuildId(buildInfoPO.getBuildId());
        unitInfoPO.setProjectId(buildInfoPO.getProjectId());
        String unitId = LogicIdUtil.bussinessId();
        unitInfoPO.setUnitId(unitId);
        unitInfoPO.setUnitName(String.format("%d单元",unitIndex));
        String unitNum = NumberHandlerUtil.numFormatToString(unitIndex,2);
        unitInfoPO.setUnitNum(unitNum);
        Date createTime = new Date();
        unitInfoPO.setCreateTime(createTime);
        unitInfoPO.setUpdateTime(createTime);
        unitInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
        //String.format("%s%s",buildInfoPO.getBuildNum(),unitNum);
        String unitAlias = getMinAvailableUnitAlias(unitAliassHasUsed,buildInfoPO.getProjectId(),buildInfoPO.getBuildNum(),unitNum);

        unitInfoPO.setUnitAlias(unitAlias);

        Integer unitGroupNum = iPropertyUnitInfoDao.getMaxUnitGroupNum(projectId);
        if (unitGroupNum == null) {
            unitGroupNum = unitIndex;
            unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString(unitGroupNum,2));
        } else {
            unitGroupNum += unitIndex;
            if (NumberHandlerUtil.isInRange(unitGroupNum, PlatformConstants.MIN_UNIT_GROUP_NUM, PlatformConstants.MAX_UNIT_GROUP_NUM)) {
                unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString(unitGroupNum,2));
            } else {
                List<String> list = iPropertyUnitInfoDao.getUnitGroupNumGroupCountMap(projectId);
                Map<String,Integer> map = new HashMap<>();
                for (String str : list){
                    String[] split = str.split(",");
                    map.put(split[0],new Integer(split[1]));
                }
                // 单元会有删除的情况，会导致项目下单元组号被删的错乱不堪，要从头补起
                for (int i = 2; i <= 99; i++) {
                    int ii = map.get(NumberHandlerUtil.numFormatToString(i, 2)) == null ? 0 : map.get(NumberHandlerUtil.numFormatToString(i, 2));
                    int iiBefore = map.get(NumberHandlerUtil.numFormatToString((i - 1), 2)) == null ? 0 : map.get(NumberHandlerUtil.numFormatToString((i - 1), 2));
                    if (ii < iiBefore) {
                        unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString(((i - 1 + unitIndex) % 99) == 0 ? 99 : ((i - 1 + unitIndex) % 99),2));
                    }
                    if (ii > iiBefore) {
                        unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString(((i - 2 + unitIndex) % 99) == 0 ? 99 : ((i - 2 + unitIndex) % 99),2));
                    }
                }
                int i1 = map.get("01") == null ? 0 : map.get("01");
                int i99 = map.get("99") == null ? 0 : map.get("99");
                if (i1 == i99) {
                    unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString(unitIndex,2));
                }
            }
            if (StringUtils.isBlank(unitInfoPO.getUnitGroupNum())) {
                unitInfoPO.setUnitGroupNum(NumberHandlerUtil.numFormatToString(unitIndex,2));
            }
        }
        return unitInfoPO;
    }


    /**
    * <desc>
    *    XXXXX.
    * </desc>
    *
    * @param  unitAliasHasUsed 当前项目已使用的单元代号
     * @param  buildNum 楼栋编号
     *@param  unitNum 单元编号
    * @return 最小可用单元代号
    * @author LewisLouis
    * @createDate 2017-12-10
    */
    private String getMinAvailableUnitAlias(List<String> unitAliasHasUsed,String projectId, String buildNum, String unitNum) {
        //首先按默认规则生成单元代号，若未被使用，则直接返回
        String defaultUnitAlias = String.format("%s%s",buildNum,unitNum);
        defaultUnitAlias = defaultUnitAlias.replaceAll("^(0+)", "");
        int unitAliasIndex = unitAliasHasUsed.indexOf(defaultUnitAlias);
        if (unitAliasIndex < 0){
            return  defaultUnitAlias;
        }

        //根据已使用的单元代号获取最小可用的单元代号
        for (int oneUnitAlias = PlatformConstants.MIN_UNIT_ALIAS;
             oneUnitAlias < PlatformConstants.MAX_UNIT_ALIAS; oneUnitAlias++){
            String unitAlias = String.valueOf(oneUnitAlias);
            if (unitAliasHasUsed.indexOf(unitAlias) < 0){
                unitAliasHasUsed.add(unitAlias); //将此复合要求的单元代号加入已使用列表
                return unitAlias;
            }
        }
        System.out.println(String.format("未找到可用的单元代号,项目Id:%s，楼栋编号：%s,单元编号：%s",
                projectId,buildNum,unitNum));
        return defaultUnitAlias;
    }

}
